package org.visionlibrary.image.filters.resampling;

import javax.media.jai.TiledImage;

import org.visionlibrary.image.acquisition.ImageFactory;
import org.visionlibrary.image.model.AbstractFilter;


public class BicubicInterpolation extends AbstractFilter {
	protected int newWidth = 256;
	protected int newHeight = 256;

	public BicubicInterpolation() {
		this(128,128);
	}
	
	public BicubicInterpolation(int newWidth, int newHeight) {
		this.newWidth = newWidth;
		this.newHeight = newHeight;
	}

	public TiledImage applyFilter(TiledImage src, TiledImage dest)
			throws IllegalArgumentException {
		if (null == src)
			throw new NullPointerException("Source image is null.");
		
		if (dest != null)
			throw new IllegalArgumentException(
					"this only works with construction:\ndest = filter.applyFilter( src, null );");

		dest = (new ImageFactory()).createCompatibleImage(src, newWidth, newHeight);

		float ratiox = src.getWidth() * 1.0f / newWidth * 1.0f;
		float ratioy = src.getHeight() * 1.0f / newHeight * 1.0f;

		int maxX = dest.getWidth();
		int maxY = dest.getHeight();
		for (int ch = 0; ch < src.getNumBands(); ch++)
			for (int x = 2; x < maxX - 2; x++)
				for (int y = 2; y < maxY - 2; y++) {
					float i = x * ratiox;
					float j = y * ratioy;
					int k = (int) i;
					int l = (int) j;

					float a = i - k;
					float b = j - l;

					float Fa0 = src.getSample(k, l - 1, ch)
							+ (src.getSample(k + 1, l - 1, ch) - src.getSample(
									k - 1, l - 1, ch))
							* a
							+ (src.getSample(k - 1, l - 1, ch) - 2
									* src.getSample(k, l - 1, ch) + src
									.getSample(k + 1, l - 1, ch)) * a * a;
					float Fa1 = src.getSample(k, l, ch)
							+ (src.getSample(k + 1, l, ch) - src.getSample(
									k - 1, l, ch))
							* a
							+ (src.getSample(k - 1, l, ch) - 2
									* src.getSample(k, l, ch) + src.getSample(
									k + 1, l, ch)) * a * a;
					float Fa2 = src.getSample(k, l + 1, ch)
							+ (src.getSample(k + 1, l + 1, ch) - src.getSample(
									k - 1, l + 1, ch))
							* a
							+ (src.getSample(k - 1, l + 1, ch) - 2
									* src.getSample(k, l + 1, ch) + src
									.getSample(k + 1, l + 1, ch)) * a * a;
					float Fab = Fa1 + (Fa2 - Fa0) * b + (Fa0 - 2 * Fa1 + Fa2)
							* b * b;

					dest.setSample(x, y, ch, ((int) Fab));
				}

		return dest;
	}

	public int getNewHeight() {
		return newHeight;
	}

	public int getNewWidth() {
		return newWidth;
	}

	public void setNewHeight(int newHeight) {
		this.newHeight = newHeight;
	}

	public void setNewWidth(int newWidth) {
		this.newWidth = newWidth;
	}
}
